﻿using System;
using System.Diagnostics;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PugLib.Threading;

namespace PugLib.UnitTest
{
    [TestClass]
    public class AsyncResultTest
    {
        private const Int32 c_iterations = 100 * 1000; // 100 thousand
        private static Int32 s_numDone;

        [TestMethod]
        public void AsyncResultTestFunctionalTest()
        {
            LongTask lt = new LongTask(5);

            // Prove that the Wait-until-done technique works
            IAsyncResult ar = lt.BeginDoTask(null, null);
            Console.WriteLine("Task completed at: {0}", lt.EndDoTask(ar));

            // Prove that the Polling technique works
            ar = lt.BeginDoTask(null, null);
            while (!ar.IsCompleted)
            {
                Console.WriteLine("Not completed yet.");
                Thread.Sleep(1000);
            }
            Console.WriteLine("Task completed at: {0}", lt.EndDoTask(ar));

            // Prove that the Callback technique works
            lt.BeginDoTask(TaskCompleted, lt);
            Console.ReadLine();
        }

        private static void TaskCompleted(IAsyncResult ar)
        {
            LongTask lt = (LongTask)ar.AsyncState;
            Console.WriteLine("Task completed at: {0}", lt.EndDoTask(ar));
            Console.WriteLine("All done, hit Enter to exit app.");
        }

        [TestMethod]
        public void AsyncResultTestPerformanceTest()
        {
            AutoResetEvent are = new AutoResetEvent(false);
            LongTask lt = new LongTask(0);

            s_numDone = 0;
            Stopwatch sw = Stopwatch.StartNew();
            for (Int32 n = 0; n < c_iterations; n++)
            {
                lt.BeginDoTask(ar =>
                {
                    if (Interlocked.Increment(ref s_numDone) == c_iterations)
                    {
                        are.Set();
                    }
                }, null);
            }
            are.WaitOne();
            Console.WriteLine("AsyncResult Time: {0}", sw.Elapsed);

            s_numDone = 0;
            Func<DateTime> doTaskDelegate = lt.DoTask;

            sw = Stopwatch.StartNew();
            for (Int32 n = 0; n < c_iterations; n++)
            {
                doTaskDelegate.BeginInvoke(ar =>
                {
                    if (Interlocked.Increment(ref s_numDone) == c_iterations)
                    {
                        are.Set();
                    }
                }, null);
            }
            are.WaitOne();
            Console.WriteLine("Delegate    Time: {0}", sw.Elapsed);
        }
    }
}